﻿using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
using System.Security.Cryptography;


namespace ControlVehiculoRFIDPA
{
    public static class Utilitario
    {
        #region --- Serializacion y Deserializacion XML ---
        /// <summary>
        /// Serializar a XML (Personalizado) un objeto cualquiera
        /// </summary>
        /// <param name="obj">Objeto a serializar</param>
        /// <param name="encoding">Codificacion del objeto</param>
        /// <returns>Objeto serializado en formato XML</returns>
        public static string SerializarToXml(this object objetoASerializar, Encoding encoding)
        {
            try
            {
                XmlSerializer xmlSerializer = new XmlSerializer(objetoASerializar.GetType());

                XmlSerializerNamespaces nmsp = new XmlSerializerNamespaces();
                nmsp.Add(string.Empty, string.Empty);

                using (MemoryStream memoryStream = new MemoryStream())
                {
                    XmlWriterSettings settings = new XmlWriterSettings();
                    settings.Encoding = encoding;
                    settings.Indent = false; // true;
                    settings.IndentChars = string.Empty; // "\t";
                    settings.NewLineChars = string.Empty; // Environment.NewLine;
                    settings.ConformanceLevel = ConformanceLevel.Document;
                    settings.OmitXmlDeclaration = false;

                    using (XmlWriter writer = XmlTextWriter.Create(memoryStream, settings))
                    {
                        xmlSerializer.Serialize(writer, objetoASerializar, nmsp);
                    }

                    string xml = encoding.GetString(memoryStream.ToArray());
                    xml = xml.Substring(0, 1).Equals("<") ? xml : xml.Substring(1);

                    return xml;
                }
            }
            catch
            {
                return string.Empty;
            }

        }

        /// <summary>
        /// Serializar a XML (Personalizado) un objeto cualquiera
        /// </summary>
        /// <param name="obj">objeto a serializar</param>
        /// <returns>Objeto serializado en formato XML</returns>
        public static string SerializarToXml(this object objetoASerializar)
        {
            return SerializarToXml(objetoASerializar, Constantes.EncodingAplicacion);
        }

        /// <summary>
        /// Deserializar un XML a un objeto T
        /// </summary>
        /// <typeparam name="T">Tipo del objeto a retornar</typeparam>
        /// <param name="xmlSerializado">Trama en formato XML</param>
        /// <param name="encoding">Codificacion de la trama</param>
        /// <returns>Objeto resultado</returns>
        public static T DeserializarTo<T>(this string xmlSerializado, Encoding encoding)
        {
            try
            {
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));

                using (MemoryStream memoryStream = new MemoryStream(encoding.GetBytes(xmlSerializado)))
                {
                    return (T)xmlSerializer.Deserialize(memoryStream);
                }
            }
            catch
            {
                return default(T);
            }
        }

        /// <summary>
        /// Deserializar un XML a un objeto T
        /// </summary>
        /// <typeparam name="T">Tipo del objeto a retornar</typeparam>
        /// <param name="xmlSerializado">Trama en formato XML</param>
        /// <returns>Objeto resultado</returns>
        public static T DeserializarTo<T>(this string xmlSerializado)
        {
            return DeserializarTo<T>(xmlSerializado, Constantes.EncodingAplicacion);
        }

        /// <summary>
        /// Convierte una trama a una arreglo de bytes
        /// </summary>
        /// <param name="xml">Trama a convertir</param>
        /// <param name="encoding">Codificacion de la trama</param>
        /// <returns>Arreglo de bytes</returns>
        public static Byte[] PersonalizadoStringToByteArray(string xml, Encoding encoding)
        {
            return encoding.GetBytes(xml);
        }

        /// <summary>
        /// Convierte una trama a una arreglo de bytes
        /// </summary>
        /// <param name="xml">Trama a convertir</param>
        /// <returns>Arreglo de bytes</returns>
        public static Byte[] PersonalizadoStringToByteArray(string xml)
        {
            return PersonalizadoStringToByteArray(xml, Constantes.EncodingAplicacion);
        }
        #endregion

        #region --- Metodos de Encriptacion y Desencriptacion 3DES ---
        /// <summary>
        /// Funcion que permite de encriptar una cadena usando algoritmo 3DES
        /// </summary>
        /// <param name="data">Cadena a encriptar</param>
        /// <param name="llave">Llave que permitira encriptar</param>
        /// <returns>Retorna Cadena encriptada</returns>
        public static string encriptar3DES(this string data, string llave)
        {
            string claveEncriptada = string.Empty;
            TripleDESCryptoServiceProvider DES = new TripleDESCryptoServiceProvider();

            byte[] bytKey = UTF8Encoding.UTF8.GetBytes(llave);

            DES.Mode = System.Security.Cryptography.CipherMode.ECB;
            DES.Key = bytKey;
            DES.Padding = PaddingMode.PKCS7;

            ICryptoTransform DESEncrypt = DES.CreateEncryptor();

            Byte[] Buffer = System.Text.ASCIIEncoding.ASCII.GetBytes(data);

            claveEncriptada = Encoding.Default.GetString(DESEncrypt.TransformFinalBlock(Buffer, 0, Buffer.Length));

            return claveEncriptada.encriptarBase64();
        }

        /// <summary>
        /// Funcion que permite de desencriptar una cadena usando algoritmo 3DES
        /// </summary>
        /// <param name="data">Cadena a ser desencriptada</param>
        /// <param name="llave">Llave que permitira desencriptar</param>
        /// <returns>Retorna Cadena desencriptada</returns>
        public static string desEncriptarDES(this string data, string llave)
        {
            TripleDESCryptoServiceProvider DES = new TripleDESCryptoServiceProvider();

            byte[] bytKey = UTF8Encoding.UTF8.GetBytes(llave);

            DES.Mode = System.Security.Cryptography.CipherMode.ECB;
            DES.Key = bytKey;
            DES.Padding = PaddingMode.PKCS7;

            ICryptoTransform DESDeEncrypt = DES.CreateDecryptor();

            Byte[] Buffer = Encoding.Default.GetBytes(data.desEncriptarBase64());

            return Encoding.Default.GetString(DESDeEncrypt.TransformFinalBlock(Buffer, 0, Buffer.Length));
        }
        #endregion

        #region --- Metodos de Encriptacion y Desencriptacion Base64 ---
        /// <summary>
        /// Funcion que permite encriptar una cadena en BASE 64
        /// </summary>
        /// <param name="data">Cadena a encriptar</param>
        /// <returns>Retorna Cadena encriptada</returns>
        public static string encriptarBase64(this string data)
        {
            byte[] bytes = Encoding.Default.GetBytes(data);
            return Convert.ToBase64String(bytes, 0, bytes.Length);
        }

        /// <summary>
        /// Funcion que permite de desencriptar una cadena en BASE 64
        /// </summary>
        /// <param name="data">Cadena a ser desencriptada</param>
        /// <returns>Retorna Cadena desencriptada</returns>
        public static string desEncriptarBase64(this string data)
        {
            byte[] bytes = Convert.FromBase64String(data);
            return Encoding.Default.GetString(bytes, 0, bytes.Length);
        }
        #endregion
    }

    public class StringWriterPersonalizado : StringWriter
    {
        public Encoding EncodingActual { get; set; }

        public override Encoding Encoding
        {
            get { return EncodingActual; }
        }
    }
}
